/*
 * @Author: 李石
 * @Date: 2024-04-24 17:25:38
 * @LastEditors: lishi
 * @LastEditTime: 2024-07-18 17:56:57
 * @Description: 
 * Copyright (c) 2024 by ${lishi0105@163.com}, All Rights Reserved. 
 */
#include "time_util.h"
#include "logger.hpp"
#include "FramePusher.hpp"

FramePusher::FramePusher(const std::string &app_, const std::string &stream_, int codec_id) :
    m_app_name(app_),
    m_stream_name(stream_),
    m_codec_id(codec_id),
    m_init_success(false)
{
    // Initialize the server
    if(codec_id != 0 && codec_id != 1){
        std::runtime_error("codec_id != 0 && codec_id != 1");
    }
    if(app_.empty() || stream_.empty()){
        std::runtime_error("app_ or stream_ is empty");
    }
    media = mk_media_create("__defaultVhost__", app_.c_str(), stream_.c_str(), 0, 0, 0);
    codec_args v_args;
    memset(&v_args, 0 , sizeof(codec_args));
    // v_args.video.width = w;
    // v_args.video.height = h;
    // v_args.video.fps = m_frame_fps;
    mk_track v_track = nullptr;
    if(codec_id == 0){
        v_track = mk_track_create(MKCodecH264, &v_args);
    }else{
        v_track = mk_track_create(MKCodecH265, &v_args);
    }
    if(v_track == nullptr){
        LOGE("mk_track_create failed");
        return;
    }
    mk_media_init_track(media,v_track);
    mk_media_init_complete(media);
    mk_track_unref(v_track);
    LOGI("FramePusher({}:{}) init success",m_app_name, m_stream_name);
    m_init_success = true;
}

FramePusher::~FramePusher()
{
    if(m_init_success){
        mk_media_release(media);
    }
    LOGI("FramePusher destroy success");
}

bool FramePusher::PushFrameData(const FrameData::Ptr frame_data)
{
    if(!m_init_success){
        LOGE("FramePusher not init success");
        return false;
    }
    if(frame_data == nullptr){
        LOGE("frame_data is nullptr");
        return false;
    }
    if(frame_data->codec_id() != m_codec_id){
        LOGE("frame_data codec_id({}) != m_codec_id({})", frame_data->codec_id(), m_codec_id);
        return false;
    }
    if(frame_data->data() == nullptr || frame_data->size() == 0){
        LOGE("frame_data data is nullptr or size is 0");
        return false;
    }
    mk_frame frame_ = nullptr;
    if(m_codec_id == 0){
        frame_ = mk_frame_create(MKCodecH264, frame_data->dts(), frame_data->pts(), (char *)(frame_data->data()), frame_data->size(), NULL, NULL);
    }else if(m_codec_id == 1){
        frame_ = mk_frame_create(MKCodecH265, frame_data->dts(), frame_data->pts(), (char *)(frame_data->data()), frame_data->size(), NULL, NULL);
    }
    if(frame_ == nullptr){
        LOGE("mk_frame_create failed");
        return false;
    }
    if(mk_media_input_frame((mk_media) media, frame_) != 1){
        LOGE("push frame error");
        mk_frame_unref(frame_);
        return false;
    }
    mk_frame_unref(frame_);
    return true;
}

bool FramePusher::PushFrameData(const uint8_t *data, size_t size, uint64_t pts_)
{
    if(!m_init_success){
        LOGE("FramePusher not init success");
        return false;
    }
    if(data == nullptr || size == 0){
        LOGE("data is nullptr or size is 0");
        return false;
    }
    uint64_t pts = pts_;
    if(pts == 0){
        pts = TimeUtil::GetMillTimestamp();
    }
    mk_frame frame_ = nullptr;
    if(m_codec_id == 0){
        frame_ = mk_frame_create(MKCodecH264, pts, pts, (char *)(data), size, NULL, NULL);
    }else if(m_codec_id == 1){
        frame_ = mk_frame_create(MKCodecH265, pts, pts, (char *)(data), size, NULL, NULL);
    }
    if(frame_ == nullptr){
        LOGE("mk_frame_create failed");
        return false;
    }
    
    if(mk_media_input_frame((mk_media) media, frame_) != 1){
        LOGE("push frame error");
        mk_frame_unref(frame_);
        return false;
    }
    mk_frame_unref(frame_);
    return true;
}

bool FramePusher::PushSeiFrame(const uint8_t *data, size_t size)
{
    if(!m_init_success){
        LOGE("FramePusher not init success");
        return false;
    }
    if(data == nullptr || size == 0){
        LOGE("data is nullptr or size is 0");
        return false;
    }
    uint64_t pts = TimeUtil::GetMillTimestamp();
    mk_frame frame_ = nullptr;
    if(m_codec_id == 0){
        frame_ = mk_frame_create(MKCodecH264, pts, pts, (char *)(data), size, NULL, NULL);
    }else if(m_codec_id == 1){
        frame_ = mk_frame_create(MKCodecH265, pts, pts, (char *)(data), size, NULL, NULL);
    }
    if(frame_ == nullptr){
        LOGE("mk_frame_create failed");
        return false;
    }
    if(mk_media_input_frame((mk_media) media, frame_) != 1){
        LOGE("push frame error");
        mk_frame_unref(frame_);
        return false;
    }
    mk_frame_unref(frame_);
    return true;
}
